#pragma once

#include <iostream>
#include <string>
#include <cstdlib>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include "Time.hpp"

const std::string gpath = "/root/code"; // 必须是存在的路径
int gprojId = 0x6666;
int gshmsize = 4096;
mode_t gmode = 0600;

std::string ToHex(key_t k)
{
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "0x%x", k);
    return buffer;
}

class ShareMemory
{
private:
    void CreateShmHelper(int shmflg)
    {
        // 1. 创建key
        _key = ::ftok(gpath.c_str(), gprojId);

        if (_key < 0)
        {
            std::cerr << "ftok error" << std::endl;
            return ;
        }

        // 2. 创建共享内存 && 获取
        // 注意：共享内存也有权限！
        _shmid = ::shmget(_key, gshmsize, shmflg);
        if (_shmid < 0)
        {
            std::cerr << "shmget error" << std::endl;
            return ;
        }
        std::cout << "shmid : " << _shmid << std::endl;
    }

public:
    ShareMemory() 
        :_shmid(-1)
        ,_key(0)
        ,_addr(nullptr)
    {}
    ~ShareMemory() {}

    void CreateShm()
    {
        if(_shmid == -1)
            CreateShmHelper(IPC_CREAT | IPC_EXCL | gmode);
    }

    void GetShm()
    {
        CreateShmHelper(IPC_CREAT);    
    }

    void AttachShm()
    {
        // 3.共享内存挂接到自己的地址空间中
        _addr = ::shmat(_shmid, nullptr, 0);
        if ((long long)_addr == -1)
        {
            std::cout << "attach error" << std::endl;
            return ;
        }
    }

    void DetachShm()
    {
        // detach
        if(_addr != nullptr)
            ::shmdt(_addr);
        std::cout << "detach done" << std::endl;
    }

    void DeleteShm()
    {
        // 3. 删除共享内存
        ::shmctl(_shmid, IPC_RMID, nullptr);
    }

    void *GetAddr()
    {
        return _addr;
    }

    void ShmMeta()
    {
        struct shmid_ds buffer;    // 系统提供的数据类型
        int n = ::shmctl(_shmid, IPC_STAT, &buffer);
        if(n < 0) return ;

        std::cout << "############################" << std::endl;
        std::cout << buffer.shm_atime << std::endl;
        std::cout << buffer.shm_cpid << std::endl;
        std::cout << buffer.shm_ctime << std::endl;
        std::cout << buffer.shm_nattch << std::endl;
        std::cout << buffer.shm_perm.__key << std::endl;
    }

private:
    int _shmid;
    key_t _key;
    void *_addr;
};

ShareMemory shm;

struct data
{
    char status[32];
    char lasttime[48];
    char image[4000];
};